import numpy as np
import pandas as pd
import re
import pm4py
import mmh3
import random
from deprecated.sphinx import deprecated
from config import RemainTimePredParameters


class BasePreprocess:
    def __init__(self):
        pass

    @staticmethod
    def _filter_data(data_frame):
        df_filtered = pd.DataFrame()
        all_cids = set(data_frame["case:concept:name"])
        cnt = 0
        for cid in all_cids:
            if cnt % 1000 == 0:
                print(cnt)
            cnt += 1
            this_df = data_frame[data_frame["case:concept:name"] == cid]
            if this_df.shape[0] >= 5:
                # df_filtered = df_filtered.append(this_df)
                df_filtered = pd.concat([df_filtered, this_df])
        return df_filtered

    def preprocess(self) -> pd.DataFrame:
        return None


class BPIC2013Preprocess(BasePreprocess):
    def __init__(self):
        super(BPIC2013Preprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="bpic2013").RAW_DATA_PATH
        self._event_log = pm4py.read_xes(self._raw_data_path)
        self.data_frame = pm4py.convert_to_dataframe(self._event_log)
        self.data_frame = BasePreprocess._filter_data(self.data_frame)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {'resource country': [], 'organization country': [], 'organization involved': [],
                          'concept:name': [], 'impact': [], 'lifecycle:transition': [], 'time:timestamp_short': [],
                          'case:concept:name': []}

        for index in range(self.data_frame.shape[0]):
            if index % 10000 == 0:
                print(index)
            data_processed['resource country'].append(self.data_frame.iloc[index]['resource country'])
            data_processed['organization country'].append(self.data_frame.iloc[index]['organization country'])
            data_processed['organization involved'].append(self.data_frame.iloc[index]['organization involved'])
            data_processed['concept:name'].append(self.data_frame.iloc[index]['concept:name'])
            data_processed['impact'].append(self.data_frame.iloc[index]['impact'])
            data_processed['lifecycle:transition'].append(self.data_frame.iloc[index]['lifecycle:transition'])

            time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index]['time:timestamp']))
            data_processed['time:timestamp_short'].append(time_stamp_short[0])
            data_processed['case:concept:name'].append(self.data_frame.iloc[index]['case:concept:name'][2:])
        df_processed = pd.DataFrame(data_processed)
        return df_processed


@deprecated(version="0.0.0", reason="数据集废弃，新数据集为BPIC 2015")
class EnvironmentalPermitPreprocess(BasePreprocess):
    def __init__(self):
        super(EnvironmentalPermitPreprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="environmental_permit").RAW_DATA_PATH
        self._event_log = pm4py.read_xes(self._raw_data_path)
        self.data_frame = pm4py.convert_to_dataframe(self._event_log)
        self.data_frame = BasePreprocess._filter_data(self.data_frame)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {'org:resource': [], 'taskName': [], 'case:caseStatus': [], 'concept:name': [],
                          'case:Includes_subCases': [], 'case:requestComplete': [], 'time:timestamp_short': [],
                          'case:concept:name': [], 'case:last_phase': []}

        for index in range(self.data_frame.shape[0]):
            if index % 10000 == 0:
                print(index)
            if self.data_frame.iloc[index]['concept:name'] is not None \
                    and self.data_frame.iloc[index]['concept:name'] is not np.NAN:
                data_processed['org:resource'].append(self.data_frame.iloc[index]['org:resource'])
                data_processed['taskName'].append(self.data_frame.iloc[index]['taskName'])
                data_processed['case:caseStatus'].append(self.data_frame.iloc[index]['case:caseStatus'])
                data_processed['concept:name'].append(self.data_frame.iloc[index]['concept:name'])
                data_processed['case:Includes_subCases'].append(self.data_frame.iloc[index]['case:Includes_subCases'])
                data_processed['case:requestComplete'].append(self.data_frame.iloc[index]['case:requestComplete'])

                time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index]['time:timestamp']))
                data_processed['time:timestamp_short'].append(time_stamp_short[0])
                data_processed['case:concept:name'].append(self.data_frame.iloc[index]['case:concept:name'])
                data_processed['case:last_phase'].append(self.data_frame.iloc[index]['case:last_phase'])

        df_processed = pd.DataFrame(data_processed)
        return df_processed


class HospitalBillingPreprocess(BasePreprocess):
    def __init__(self):
        super(HospitalBillingPreprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="hospital_billing").RAW_DATA_PATH
        self.data_frame = pd.read_csv(self._raw_data_path)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {"case:concept:name": [], "concept:name": [], "time:timestamp_short": []}
        for index in range(self.data_frame.shape[0]):
            if index % 10000 == 0:
                print(index)
            data_processed["case:concept:name"].append(mmh3.hash(self.data_frame.iloc[index]["case:concept:name"]))
            data_processed["concept:name"].append(self.data_frame.iloc[index]["concept:name"])
            time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index]['time:timestamp']))
            data_processed['time:timestamp_short'].append(time_stamp_short[0])

        df_processed = pd.DataFrame(data_processed)
        return df_processed


class BPIC2015Preprocess(BasePreprocess):
    def __init__(self):
        super(BPIC2015Preprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="bpic2015").RAW_DATA_PATH
        self._event_log = pm4py.read_xes(self._raw_data_path)
        self.data_frame = pm4py.convert_to_dataframe(self._event_log)
        self.data_frame = BasePreprocess._filter_data(self.data_frame)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {"case:concept:name": [], "concept:name": [], "time:timestamp_short": [], "org:resource": [],
                          "monitoringResource": [], "case:caseStatus": [], "case:last_phase": [],
                          "case:requestComplete": []
                          }
        for index in range(self.data_frame.shape[0]):
            if index % 10000 == 0:
                print(index)
            data_processed["case:concept:name"].append(self.data_frame.iloc[index]["case:concept:name"])
            data_processed["concept:name"].append(self.data_frame.iloc[index]["concept:name"])
            data_processed["org:resource"].append(self.data_frame.iloc[index]["org:resource"])
            data_processed["monitoringResource"].append(self.data_frame.iloc[index]["monitoringResource"])
            data_processed["case:caseStatus"].append(self.data_frame.iloc[index]["case:caseStatus"])
            data_processed["case:last_phase"].append(self.data_frame.iloc[index]["case:last_phase"])
            data_processed["case:requestComplete"].append(self.data_frame.iloc[index]["case:requestComplete"])
            time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index]['time:timestamp']))
            data_processed['time:timestamp_short'].append(time_stamp_short[0])

        df_processed = pd.DataFrame(data_processed)
        return df_processed


class BPIC2012Preprocess(BasePreprocess):
    def __init__(self):
        super(BPIC2012Preprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="bpic2012").RAW_DATA_PATH
        self.data_frame = pd.read_csv(self._raw_data_path)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {'lifecycle:transition': [], 'time:timestamp_short': [], 'concept:name': [],
                          'case:concept:name': [], 'case:AMOUNT_REQ': []}

        for index in range(self.data_frame.shape[0]):
            if index % 2000 == 0:
                print(index)
            data_processed['lifecycle:transition'].append(self.data_frame.iloc[index]['lifecycle:transition'])
            data_processed['concept:name'].append(self.data_frame.iloc[index]['concept:name'])
            data_processed['case:AMOUNT_REQ'].append(self.data_frame.iloc[index]['case:AMOUNT_REQ'])

            time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index]['time:timestamp']))
            data_processed['time:timestamp_short'].append(time_stamp_short[0])
            data_processed['case:concept:name'].append(self.data_frame.iloc[index]['case:concept:name'])
        df_processed = pd.DataFrame(data_processed)
        return df_processed


class BPIC2018Preprocess(BasePreprocess):
    def __init__(self):
        super(BPIC2018Preprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="bpic2018").RAW_DATA_PATH
        self.data_frame = pd.read_csv(self._raw_data_path)

    def preprocess_v0(self) -> pd.DataFrame:
        data_processed = {}
        for col in self.data_frame.columns:
            if col == "time:timestamp":
                data_processed["time:timestamp_short"] = []
            else:
                data_processed[col] = []
        sample_cids = set()
        remove_cids = set()
        for index in range(self.data_frame.shape[0]):
            if index % 5000 == 0:
                print(index)
            cid = self.data_frame.iloc[index]["case:concept:name"]
            if cid in remove_cids:
                continue
            if cid not in sample_cids:
                prob = random.uniform(0, 1)
                if prob > 0.1:
                    remove_cids.add(cid)
                    continue
                else:
                    sample_cids.add(cid)
            for col in self.data_frame.columns:
                if col == "time:timestamp":
                    time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index][col]))
                    data_processed['time:timestamp_short'].append(time_stamp_short[0])
                elif col == "case:concept:name":
                    data_processed["case:concept:name"].append(
                        mmh3.hash(self.data_frame.iloc[index]["case:concept:name"]))
                else:
                    data_processed[col].append(self.data_frame.iloc[index][col])
        df_processed = pd.DataFrame(data_processed)
        return df_processed

    def preprocess(self) -> pd.DataFrame:
        return self.data_frame


class BPIC2019Preprocess(BasePreprocess):
    def __init__(self):
        super(BPIC2019Preprocess, self).__init__()
        self._raw_data_path = RemainTimePredParameters(dataset_name="bpic2019").RAW_DATA_PATH
        self.data_frame = pd.read_csv(self._raw_data_path)

    def preprocess(self) -> pd.DataFrame:
        data_processed = {}
        for col in self.data_frame.columns:
            if col == "time:timestamp":
                data_processed["time:timestamp_short"] = []
            else:
                data_processed[col] = []
        for index in range(self.data_frame.shape[0]):
            if index % 1000 == 0:
                print(index)
            for col in self.data_frame.columns:
                if col == "time:timestamp":
                    time_stamp_short = re.split("\.|\+", str(self.data_frame.iloc[index][col]))
                    data_processed['time:timestamp_short'].append(time_stamp_short[0])
                elif col == "case:concept:name":
                    data_processed["case:concept:name"].append(
                        mmh3.hash(self.data_frame.iloc[index]["case:concept:name"]))
                else:
                    data_processed[col].append(self.data_frame.iloc[index][col])
        df_processed = pd.DataFrame(data_processed)
        return df_processed
